package br.ufpe.cin.rdfilter.util;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import br.ufpe.cin.rdfilter.feedback.Annotation;
import br.ufpe.cin.rdfilter.feedback.Feedback;
import br.ufpe.cin.rdfilter.model.Manager;
import br.ufpe.cin.rdfilter.model.Query;
import br.ufpe.cin.rdfilter.model.User;
import br.ufpe.cin.rdfilter.query.QueryManager;

public class UserSimilarity {
	private double exp = 0.0;
	private double nonexp = 0.0;
	private List<Feedback> feedbackList = new ArrayList<Feedback>();
	private List<Feedback> feedback;
	private List<Annotation> annotation;
	Set<String> users = new LinkedHashSet<String>();
	private int nUser = 0;
	private List<ArrayList> matriz = new ArrayList<ArrayList>();
	private double[][] matrix = null;
	private Manager m = new Manager();
	
	public List<Annotation> getAnnotation() {
		return annotation;
	}

	public void setAnnotation(List<Annotation> annotation) {
		this.annotation = annotation;
	}

	public double getMatriz(int linha, int coluna) {
		return matrix[linha][coluna];
	}

	@SuppressWarnings("unchecked")
	public void setMatriz(int linha, int coluna, double valor) {
		matrix[linha][coluna] = valor;
	}

	public List<Annotation> getExp(String user) {
		List<Annotation> annotExp = new ArrayList<Annotation>();
		annotation = new ArrayList<Annotation>();
		for (int i = 0; i < feedbackList.size(); i++) {
			annotation = feedbackList.get(i).getAnnotation();
			for (int j = 0; j < annotation.size(); j++) {
				if (annotation.get(j).getIdUser().equals(user)) {
					if (annotation.get(j).getType().equals("True Positive")
							|| annotation.get(j).getType()
									.equals("False Negative")) {
						annotExp.add(annotation.get(j));
					}
				}
			}
		}
		return annotExp;
	}

	public List<Annotation> getNonExp(String user) {
		List<Annotation> annotNonExp = new ArrayList<Annotation>();
		annotation = new ArrayList<Annotation>();
		for (int i = 0; i < feedbackList.size(); i++) {
			annotation = feedbackList.get(i).getAnnotation();
			for (int j = 0; j < annotation.size(); j++) {
				if (annotation.get(j).getIdUser().equals(user)) {
					if (annotation.get(j).getType().equals("False Positive")) {
						annotNonExp.add(annotation.get(j));
					}
				}
			}
		}
		return annotNonExp;
	}

	public void getFeedback() {
		QueryManager qm = new QueryManager();
		qm.setDir(new File("list.txt"));
		List<String> queries = qm.loadQuery();

		LoadFeedback lf = new LoadFeedback();
		feedback = lf.loadAll(queries);

		for (int i = 0; i < queries.size(); i++) {

			Feedback f = null;
			annotation = new ArrayList<Annotation>();
			feedbackList = new ArrayList<Feedback>();
			try {

				FileReader reader = new FileReader("notes.txt");
				BufferedReader in = new BufferedReader(reader);
				String line = null;
				String[] result = null;
				// List<Annotation> annotation = new ArrayList<Annotation>();
				Annotation annot = null;
				List<String> tokens;
				List<String> terms;

				while ((line = in.readLine()) != null) {
					annot = new Annotation();
					terms = new ArrayList<String>();
					tokens = new ArrayList<String>();
					result = line.split(";");
					for (int j = 0; j < result.length; j++) {
						tokens.add(result[j]);
					}
					if (tokens.get(0).equals(queries.get(i))) {
						annot.setIdQuery(tokens.get(0));
						annot.setIdUser(tokens.get(1));
						annot.setType(tokens.get(tokens.size() - 2));
						annot.setConfidence(tokens.get(tokens.size() - 1));
						for (int k = 2; k < tokens.size() - 2; k++) {
							terms.add(tokens.get(k));
						}
						annot.setTerms(terms);

						annotation.add(annot);
					}
				}
				in.close();
				reader.close();

				f = new Feedback("", annotation);
				// feedbackList.add(f);
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
			feedbackList.add(f);
		}

	}

	public void calculateSimilarity() {
		try {
			double sim = 0.0;
			FileReader reader = new FileReader("notes.txt");
			BufferedReader in = new BufferedReader(reader);
			String line = null;
			String[] result = null;

			while ((line = in.readLine()) != null) {
				result = line.split(";");
				users.add(result[1]);
			}
			List<String> users2 = new ArrayList(users);
			System.out.println(users.size());

			this.startMatrix();

			List<User> listUsers = new ArrayList<User>();
			User u = m.getUser(users2.get(0));
			for(int i=0;i<users.size();i++){
				listUsers.add(m.getUser(users2.get(i)));
			}
			
			
			for (int i = 0; i < listUsers.size(); i++) {
				for (int j = i+1; j < listUsers.size(); j++) {
					sim = sim2(listUsers.get(i),listUsers.get(j));
					m.addSimilarity(sim, listUsers.get(j), listUsers.get(j));
				}
				}
			m.stop();
			/*
			for (int i = 0; i < users2.size(); i++) {
				for (int j = i; j < users2.size(); j++) {
					if (!users2.get(i).equals(users2.get(j))) {
						sim = sim(users2.get(i), users2.get(j));
						this.setMatriz(i, j, sim);
					}
				}
			}*/

			for (int k = 0; k < matrix.length; k++) {
				for (int l = 0; l < matrix.length; l++)
					System.out.println("Linha " + k + " Coluna " + l + ": "
							+ matrix[k][l]);
			}
			in.close();
			reader.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private Double sim(String user1, String user2) {
		int intersection = 0;
		int union = 0;
		List<Annotation> e1 = this.getExp(user1);
		List<Annotation> e2 = this.getExp(user2);

		List<Annotation> ue1 = this.getNonExp(user1);
		List<Annotation> ue2 = this.getNonExp(user2);
		
		union = e1.size() + e2.size();
		if(union!=0){
			for (int i = 0; i < e1.size(); i++) {
				for (int j = 0; j < e2.size(); j++) {
					if (e1.get(i).getTerms().get(0)
							.equals(e2.get(j).getTerms().get(0))) {
						intersection++;
					}
				}
			}
		
		exp = ((double) intersection / union);
		}
		else exp = 0.0;
		
		intersection=0;
		
		union = ue1.size() + ue2.size();
		if(union!=0){
			for (int i = 0; i < ue1.size(); i++) {
				for (int j = 0; j < ue2.size(); j++) {
					if (ue1.get(i).getTerms().get(0)
							.equals(ue2.get(j).getTerms().get(0))) {
						intersection++;
					}
				}
			}
		nonexp = ((double) intersection / union);
		} else nonexp = 0.0;
		
		return 0.5*exp+0.5*nonexp;
	}

	private Double sim2(User u1, User u2) {
		List<br.ufpe.cin.rdfilter.model.Feedback> e1 = m.getExp(u1);
		List<br.ufpe.cin.rdfilter.model.Feedback> e2 = m.getExp(u2);
		
		List<br.ufpe.cin.rdfilter.model.Feedback> ue1 = m.getNonExp(u1);
		List<br.ufpe.cin.rdfilter.model.Feedback> ue2 = m.getNonExp(u2);
		
		int intersection = 0;
		int union = 0;
//		List<Annotation> e1 = this.getExp(user1);
//		List<Annotation> e2 = this.getExp(user2);
//
//		List<Annotation> ue1 = this.getNonExp(user1);
//		List<Annotation> ue2 = this.getNonExp(user2);
		
		union = e1.size() + e2.size();
		if(union!=0){
			for (int i = 0; i < e1.size(); i++) {
				for (int j = 0; j < e2.size(); j++) {
					System.out.println(e1.get(i).getTerm() + " --- " + e2.get(j).getTerm());
					if (e1.get(i).getTerm()
							.equals(e2.get(j).getTerm())) {
						intersection++;
					}
				}
			}
		
		exp = ((double) intersection / union);
		}
		else exp = 0.0;
		
		intersection=0;
		
		union = ue1.size() + ue2.size();
		if(union!=0){
			for (int i = 0; i < ue1.size(); i++) {
				for (int j = 0; j < ue2.size(); j++) {
					if (ue1.get(i).getTerm()
							.equals(ue2.get(j).getTerm())) {
						intersection++;
					}
				}
			}
		nonexp = ((double) intersection / union);
		} else nonexp = 0.0;
		
		return 0.5*exp+0.5*nonexp;
	}
	
	public void startMatrix() {
		matrix = new double[users.size()][users.size()];
	}
	

	public static void main(String[] args) {
		UserSimilarity us = new UserSimilarity();
//		us.getFeedback();
		Manager m = new Manager();
		Query q = m.getQuery("query02");
		User u1 = m.getUser("Helio");
		User u2 = m.getUser("Alberto");
		List<br.ufpe.cin.rdfilter.model.Feedback> feedbackList = m.getFeedback(q);
		System.out.println(feedbackList.get(0).getType());
		us.calculateSimilarity();
	}

}
